/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.constant.enums.IsfdBusinessDatabaseTypeEnum;
import com.comac.ins.isfd.domain.IsfdDatabaseTypeManagement;
import com.comac.ins.isfd.domain.bo.IsfdDatabaseTypeManagementBo;
import com.comac.ins.isfd.domain.bo.query.IsfdDatabaseTypeManagementQueryBo;
import com.comac.ins.isfd.domain.vo.IsfdDatabaseTypeManagementVo;
import com.comac.ins.isfd.mapper.IsfdDatabaseTypeManagementMapper;
import com.comac.ins.isfd.service.IIsfdDatabaseModelTreeService;
import com.comac.ins.isfd.service.IIsfdDatabaseTypeManagementService;
import com.comac.ins.isfd.util.TreeUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 要素库类型管理Service业务层处理
 *
 * @author hxloongs
 * @date 2025-02-27
 */
@RequiredArgsConstructor
@Service
public class IsfdDatabaseTypeManagementServiceImpl implements IIsfdDatabaseTypeManagementService {

    @Autowired
    private IsfdDatabaseTypeManagementMapper baseMapper;

    @Autowired
    private IIsfdDatabaseModelTreeService iIsfdDatabaseModelTreeService;

    @Override
    public List<IsfdDatabaseTypeManagementVo> tree(String databaseName) {
        IsfdDatabaseTypeManagementBo bo = new IsfdDatabaseTypeManagementBo();
        bo.setDatabaseName(databaseName);
        List<IsfdDatabaseTypeManagementVo> allNodes = this.queryList(bo);
        if (CollectionUtils.isEmpty(allNodes)) {
            return new ArrayList<>();
        }
        if (StringUtils.isNotBlank(databaseName)) {
            List<Long> topIds = allNodes.stream().map(IsfdDatabaseTypeManagementVo::getTopId).toList();
            allNodes = baseMapper.selectByTopIds(topIds);
        }
        return TreeUtils.buildDatabaseTypeTree(allNodes);
    }

    @Override
    public IsfdDatabaseTypeManagementVo querySingleVoById(Long id) {
        return baseMapper.selectVoById(id);
    }

    @Override
    public IsfdDatabaseTypeManagementVo queryById(Long id) {
        IsfdDatabaseTypeManagementVo isfdDatabaseTypeManagementVo = baseMapper.selectVoById(id);
        if (isfdDatabaseTypeManagementVo != null && isfdDatabaseTypeManagementVo.getLevel() != 1) {
            Long parentId = isfdDatabaseTypeManagementVo.getParentId();
            IsfdDatabaseTypeManagementVo parent = this.queryById(parentId);
            isfdDatabaseTypeManagementVo.setParentDatabaseName(parent.getDatabaseName());
        }
        return isfdDatabaseTypeManagementVo;
    }

    @Override
    public TableDataInfo<IsfdDatabaseTypeManagementVo> queryPageList(IsfdDatabaseTypeManagementQueryBo queryBo) {
        PageQuery pageQuery = new PageQuery();
        pageQuery.setPageNum(queryBo.getPageNum());
        pageQuery.setPageSize(queryBo.getPageSize());
        if (StringUtils.isNotBlank(queryBo.getIsAsc())) {
            pageQuery.setIsAsc(queryBo.getIsAsc());
        }
        LambdaQueryWrapper<IsfdDatabaseTypeManagement> lqw = buildQueryWrapper(queryBo);
        Page<IsfdDatabaseTypeManagementVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        result.getRecords().forEach(r -> {
            if (r.getLevel() != 1) {
                Long parentId = r.getParentId();
                IsfdDatabaseTypeManagementVo parent = this.queryById(parentId);
                r.setParentDatabaseName(parent.getDatabaseName());
            }
        });
        return TableDataInfo.build(result);
    }

    @Override
    public List<IsfdDatabaseTypeManagementVo> queryList(IsfdDatabaseTypeManagementBo bo) {
        LambdaQueryWrapper<IsfdDatabaseTypeManagement> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<IsfdDatabaseTypeManagement> buildQueryWrapper(IsfdDatabaseTypeManagementQueryBo queryBo) {
        LambdaQueryWrapper<IsfdDatabaseTypeManagement> lqw = Wrappers.lambdaQuery();
        if (queryBo.getId() != null) {
            lqw.and(lqw1 -> lqw1.eq(IsfdDatabaseTypeManagement::getId, queryBo.getId())
                .or().eq(IsfdDatabaseTypeManagement::getParentId, queryBo.getId()));
        }
        lqw.eq(queryBo.getParentId() != null, IsfdDatabaseTypeManagement::getParentId, queryBo.getParentId());
        lqw.eq(queryBo.getTopId() != null, IsfdDatabaseTypeManagement::getTopId, queryBo.getTopId());
        lqw.like(StringUtils.isNotBlank(queryBo.getDatabaseName()), IsfdDatabaseTypeManagement::getDatabaseName, queryBo.getDatabaseName());
        lqw.eq(queryBo.getLevel() != null, IsfdDatabaseTypeManagement::getLevel, queryBo.getLevel());
        lqw.eq(StringUtils.isNotBlank(queryBo.getDescription()), IsfdDatabaseTypeManagement::getDescription, queryBo.getDescription());
        if (queryBo.getStartCreateTime() != null && queryBo.getEndCreateTime() != null) {
            lqw.between(IsfdDatabaseTypeManagement::getCreateTime, queryBo.getStartCreateTime(), queryBo.getEndCreateTime());
        }
        lqw.orderByDesc(IsfdDatabaseTypeManagement::getTopId)
            .orderByAsc(IsfdDatabaseTypeManagement::getCreateTime);
        return lqw;
    }

    private LambdaQueryWrapper<IsfdDatabaseTypeManagement> buildQueryWrapper(IsfdDatabaseTypeManagementBo bo) {
        LambdaQueryWrapper<IsfdDatabaseTypeManagement> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getParentId() != null, IsfdDatabaseTypeManagement::getParentId, bo.getParentId());
        lqw.eq(bo.getTopId() != null, IsfdDatabaseTypeManagement::getTopId, bo.getTopId());
        lqw.like(StringUtils.isNotBlank(bo.getDatabaseName()), IsfdDatabaseTypeManagement::getDatabaseName, bo.getDatabaseName());
        lqw.eq(bo.getLevel() != null, IsfdDatabaseTypeManagement::getLevel, bo.getLevel());
        lqw.eq(StringUtils.isNotBlank(bo.getDescription()), IsfdDatabaseTypeManagement::getDescription, bo.getDescription());
        lqw.orderByDesc(IsfdDatabaseTypeManagement::getCreateTime);
        return lqw;
    }

    @Override
    public Boolean insertByBo(IsfdDatabaseTypeManagementBo bo) {
        if (bo.getLevel() >= 2 && bo.getParentId() == 0) {
            throw new BaseException("创建二级库，必须关联一级库！");
        }
        String databaseName = bo.getDatabaseName();
        IsfdDatabaseTypeManagementBo queryBo = new IsfdDatabaseTypeManagementBo();
        queryBo.setDatabaseName(databaseName);
        List<IsfdDatabaseTypeManagementVo> oldList = this.queryList(queryBo);
        if (!CollectionUtils.isEmpty(oldList)) {
            throw new BaseException("要素库名称已经存在，请更换名称后重试！");
        }
        IsfdDatabaseTypeManagement add = MapstructUtils.convert(bo, IsfdDatabaseTypeManagement.class);
        baseMapper.insert(add);
        if (bo.getLevel() >= 2) {
            IsfdDatabaseTypeManagementVo parent = this.queryById(bo.getParentId());
            add.setTopId(parent.getTopId());
        } else {
            add.setTopId(add.getId());
        }
        baseMapper.updateById(add);
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateByBo(IsfdDatabaseTypeManagementBo bo) {
        Long id = bo.getId();
        String databaseName = bo.getDatabaseName();
        IsfdDatabaseTypeManagementBo queryBo = new IsfdDatabaseTypeManagementBo();
        queryBo.setDatabaseName(databaseName);
        List<IsfdDatabaseTypeManagementVo> oldList = this.queryList(queryBo);
        // 1. 名字幂等校验
        if (!CollectionUtils.isEmpty(oldList)) {
            for (IsfdDatabaseTypeManagementVo old : oldList) {
                if (!old.getId().equals(bo.getId())) {
                    throw new BaseException("要素库名称已经存在，请更换名称后重试！");
                }
            }
        }

        if(id.equals(bo.getParentId())){
            throw new BaseException("父节点不能选择自己！");
        }

        IsfdDatabaseTypeManagementVo isfdDatabaseTypeManagementVo = this.queryById(bo.getId());
        // 2. 校验是否level字段发生改变
        if (isfdDatabaseTypeManagementVo.getLevel() == 1) {
            List<IsfdDatabaseTypeManagementVo> children = baseMapper.selectVoList(new LambdaQueryWrapper<IsfdDatabaseTypeManagement>()
                .eq(IsfdDatabaseTypeManagement::getParentId, id));
            if (!CollectionUtils.isEmpty(children)) {
                throw new BaseException("当前一级库已经关联了二级库，不能修改!");
            }
            // 把一级库修改为二级库
            if (bo.getLevel() == 2) {
                bo.setTopId(bo.getParentId());
            }
        } else {
            // 把二级库修改为一级库
            if (bo.getLevel() == 1) {
                bo.setTopId(id);
                bo.setParentId(0L);
            }
        }

        // 3.校验在模型中是否已经关联上
        IsfdBusinessDatabaseTypeEnum isfdBusinessDatabaseTypeEnum = IsfdBusinessDatabaseTypeEnum.DATABASE_2;
        if (isfdDatabaseTypeManagementVo.getLevel() == 1) {
            isfdBusinessDatabaseTypeEnum = IsfdBusinessDatabaseTypeEnum.DATABASE_1;
        }
        iIsfdDatabaseModelTreeService.checkIfNodeExist(isfdBusinessDatabaseTypeEnum, id, isfdDatabaseTypeManagementVo.getDatabaseName());

        IsfdDatabaseTypeManagement update = MapstructUtils.convert(bo, IsfdDatabaseTypeManagement.class);
        return baseMapper.updateById(update) > 0;
    }

    @Override
    @Transactional
    public Boolean deleteWithValidById(Long id) {
        IsfdDatabaseTypeManagementVo isfdDatabaseTypeManagementVo = baseMapper.selectVoById(id);
        if (isfdDatabaseTypeManagementVo == null) {
            throw new BaseException("删除的数据不存在，请确认后重试！");
        }
        Long level = isfdDatabaseTypeManagementVo.getLevel();
        IsfdBusinessDatabaseTypeEnum isfdBusinessDatabaseTypeEnum = IsfdBusinessDatabaseTypeEnum.DATABASE_2;
        if (level == 1) {
            isfdBusinessDatabaseTypeEnum = IsfdBusinessDatabaseTypeEnum.DATABASE_1;
            IsfdDatabaseTypeManagementBo bo = new IsfdDatabaseTypeManagementBo();
            bo.setParentId(id);
            List<IsfdDatabaseTypeManagementVo> children = this.queryList(bo);
            if (!CollectionUtils.isEmpty(children)) {
                throw new BaseException("当前的数据库是一级库，存在关联的二级子数据库，请删除关联的二级子库后再删除当前库！");
            }
        }
        iIsfdDatabaseModelTreeService.checkIfNodeExist(isfdBusinessDatabaseTypeEnum, id, isfdDatabaseTypeManagementVo.getDatabaseName());
        return baseMapper.deleteById(id) > 0;
    }

    @Override
    public List<IsfdDatabaseTypeManagementVo> queryListByIds(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return new ArrayList<>();
        }
        return baseMapper.selectVoList(new LambdaQueryWrapper<IsfdDatabaseTypeManagement>().in(IsfdDatabaseTypeManagement::getId, ids));
    }

    @Override
    public List<IsfdDatabaseTypeManagementVo> queryTreeByIds(Collection<Long> ids) {
        List<IsfdDatabaseTypeManagementVo> result = new ArrayList<>();
        List<IsfdDatabaseTypeManagementVo> databaseList = this.queryListByIds(ids);
        if (!CollectionUtils.isEmpty(databaseList)) {
            Set<Long> existingIds = new HashSet<>();
            List<IsfdDatabaseTypeManagementVo> allDatabaseList = new ArrayList<>();
            for (IsfdDatabaseTypeManagementVo vo : databaseList) {
                // 添加当前节点
                if (existingIds.add(vo.getId())) {
                    allDatabaseList.add(vo);
                }
                // 向上遍历所有父节点直到根节点
                Long parentId = vo.getParentId();
                while (parentId != null && parentId != 0L) {
                    IsfdDatabaseTypeManagementVo parentVo = this.queryById(parentId);
                    if (parentVo == null) {
                        break;
                    }
                    if (existingIds.add(parentVo.getId())) {
                        allDatabaseList.add(parentVo);
                    }
                    parentId = parentVo.getParentId();
                }
            }
            result = TreeUtils.buildDatabaseTypeTree(allDatabaseList);
        }
        return result;
    }

    @Override
    public List<IsfdDatabaseTypeManagementVo> queryAllTreeByIds(Collection<Long> ids) {
        List<IsfdDatabaseTypeManagementVo> result = new ArrayList<>();
        List<IsfdDatabaseTypeManagementVo> databaseList = this.queryListByIds(ids);
        if (!CollectionUtils.isEmpty(databaseList)) {
            Set<Long> topIds = databaseList.stream().map(IsfdDatabaseTypeManagementVo::getTopId).collect(Collectors.toSet());
            List<IsfdDatabaseTypeManagementVo> allDatabaseList = this.queryListByTopIds(topIds);
            result = TreeUtils.buildDatabaseTypeTree(allDatabaseList);
        }
        return result;
    }

    @Override
    public List<IsfdDatabaseTypeManagementVo> queryListByTopIds(Collection<Long> topIds) {
        if (CollectionUtils.isEmpty(topIds)) {
            return new ArrayList<>();
        }
        return baseMapper.selectVoList(new LambdaQueryWrapper<IsfdDatabaseTypeManagement>().in(IsfdDatabaseTypeManagement::getTopId, topIds));
    }

    @Override
    public List<IsfdDatabaseTypeManagementVo> queryListByDataBaseName(String databaseName) {
        IsfdDatabaseTypeManagementVo targetVo = baseMapper.selectVoOne(new LambdaQueryWrapper<IsfdDatabaseTypeManagement>()
            .eq(IsfdDatabaseTypeManagement::getDatabaseName, databaseName));
        if (targetVo == null) {
            return new ArrayList<>();
        }
        Long topId = targetVo.getTopId();
        return this.queryListByTopIds(Collections.singleton(topId));
    }

}
